﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace QuickExcel
{
    public partial class UnitConverter : Form
    {
        string[] sCategories = new string[] {"Angle","Memory","Length","Energy","Force","Liquid","Mass","Surface","Time","Volume"};
        string[] sAngle = new string[] {"Degree","Grad","Minute","Radian","Revolution","Second"};
        string[] sMemory = new string[] {"Bit","Kilobit","Megabit","Gigabit","Terabit","Petabit","Exabit","BYTE","KILOBYTE","MEGABYTE","GIGABYTE","TERABYTE","PETABYTE","EXABYTE"};
        string[] sLength = new string[] {"Foot","Inch","Meter","Nautical mile","Statute mile","Yard"};
        string[] sEnergy = new string[] {"BTU","Calorie (IT)","Calorie (Th'mic)","Electron volt","Erg","Foot-pound","Horsepower-hour","Joule","Watt-hour"};
        string[] sForces = new string[] {"Dyne","Newton","Pound force"};
        string[] sLiquid = new string[] {"Cup","Gallon","Gallon (Imp)","Liter","Ounce","Ounce (Imp)","Pint","Pint (Imp)","Quart","Quart (Imp)","Tablespoon","Teaspoon"};
        string[] sMass = new string[] {"Caret","Grain","Gram","Ounce (Avdp)","Ounce (Troy)","Pound (Avdp)","Pound (Troy)","Stone","Ton"};
        string[] sSurface = new string[] {"Acre","Hectare","Sq Foot","Sq Inch","Sq Meter","Sq Miles","Sq Yard"};
        string[] sTime = new string[] {"Celsius","Fahrenheit","Kelvin"};
        string[] sVolume = new string[] {"Day","Hour","Leap Year","Minute","Second","Year"};
        string[] sMetricPrefix = new string[] { "Exa (1E+18)", "Peta (1E+15)", "Tera (1E+12)", "Giga (1E+09", "Mega (1E+06)", "Kilo (1E+03)", "Hecto (1E+02)", "Dekao (1E+01)", "(None)", "Deci (1E-01)", "Centi (1E-02)", "Milli (1E-03)", "Micro (1E-06)", "Nano (1E-09)", "Pico (1E-12)", "Femto (1E-15)", "Atto (1E-18)" };        
        
        int[] iFactors = new int[] { 18, 15, 12, 9, 6, 3, 2, 1, 0, -1, -2, -3, -6, -9, -12, -15, -18 };
        
        Dictionary<string, string> ReplaceToCategory = new Dictionary<string, string>();
        Dictionary<string, int> MetricFactors = new Dictionary<string, int>();
        Dictionary<string, string[]> ArrayCollection = new Dictionary<string, string[]>();
        
        public UnitConverter()
        {
            InitializeComponent();
        }

        private void UnitConverter_Load(object sender, EventArgs e)
        {            
            comCategory.Items.Clear();

            foreach(string curCategory in sCategories)            
                comCategory.Items.Add(curCategory);
            
            foreach(string curPre in sMetricPrefix)
            {
                comPreFrom.Items.Add(curPre);
                comPreTo.Items.Add(curPre);
            }

            txtSource.Text = Globals.ThisAddIn.Application.Selection.Address;
            txtResult.Text = txtSource.Text;

            lstFrom.Items.Clear();
            lstTo.Items.Clear();
            chkOverwrite.Checked = false;

            comPreFrom.Enabled = false;
            comPreTo.Enabled = false;

            ArrayCollection.Add("Angle", sAngle);
            ArrayCollection.Add("Memory", sMemory);
            ArrayCollection.Add("Length", sLength);
            ArrayCollection.Add("Energy", sEnergy);
            ArrayCollection.Add("Force", sForces);
            ArrayCollection.Add("Liquid", sLiquid);
            ArrayCollection.Add("Mass", sMass);
            ArrayCollection.Add("Surface", sSurface);
            ArrayCollection.Add("Time", sTime);
            ArrayCollection.Add("Volume", sVolume);
            
            ReplaceToCategory.Add("Nautical mile", "NauticalMile");
            ReplaceToCategory.Add("Statute mile", "StatuteMile");
            ReplaceToCategory.Add("Calorie (IT)", "CalorieIT");
            ReplaceToCategory.Add("Calorie (Th'mic)", "CalorieTh_mic");
            ReplaceToCategory.Add("Electron volt", "ElectronVolt");
            ReplaceToCategory.Add("Foot-pound", "FootPound");
            ReplaceToCategory.Add("Horsepower-hour", "HorsepowerHour");
            ReplaceToCategory.Add("Watt-hour", "WattHour");
            ReplaceToCategory.Add("Pound force", "PoundForce");
            ReplaceToCategory.Add("Gallon (Imp)", "GallonImp");
            ReplaceToCategory.Add("Ounce (Imp)", "OunceImp");
            ReplaceToCategory.Add("Pint (Imp)", "PintImp");
            ReplaceToCategory.Add("Quart (Imp)", "QuartImp");
            ReplaceToCategory.Add("Ounce (Avdp)", "OunceAvdp");
            ReplaceToCategory.Add("Ounce (Troy)", "OunceTroy");
            ReplaceToCategory.Add("Pound (Avdp)", "PoundAvdp");
            ReplaceToCategory.Add("Pound (Troy)", "PoundTroy");
            ReplaceToCategory.Add("Sq Foot", "SqFoot");
            ReplaceToCategory.Add("Sq Inch", "SqInch");
            ReplaceToCategory.Add("Sq Meter", "SqMeter");
            ReplaceToCategory.Add("Sq Miles", "SqMiles");
            ReplaceToCategory.Add("Sq Yard", "SqYard");
            ReplaceToCategory.Add("Leap Year", "LeapYear");
            ReplaceToCategory.Add("Cubic Foot", "CubicFoot");
            ReplaceToCategory.Add("Cubic Inch", "CubicInch");
            ReplaceToCategory.Add("Cubic Meter", "CubicMeter");
            ReplaceToCategory.Add("Cubic Yard", "CubicYard");
            
            MetricFactors.Add("Exa (1E+18)", 18);
            MetricFactors.Add("Peta (1E+15)", 15);
            MetricFactors.Add("Tera (1E+12)", 12);
            MetricFactors.Add("Giga (1E+09", 9);
            MetricFactors.Add("Mega (1E+06)", 6);
            MetricFactors.Add("Kilo (1E+03)", 3);
            MetricFactors.Add("Hecto (1E+02)", 2);
            MetricFactors.Add("Dekao (1E+01)", 1);
            MetricFactors.Add("(None)", 0);
            MetricFactors.Add("Deci (1E-01)", -1);
            MetricFactors.Add("Centi (1E-02)", -2);
            MetricFactors.Add("Milli (1E-03)", -3);
            MetricFactors.Add("Micro (1E-06)", -6);
            MetricFactors.Add("Nano (1E-09)", -9);
            MetricFactors.Add("Pico (1E-12)", -12);
            MetricFactors.Add("Femto (1E-15)", -15);
            MetricFactors.Add("Atto (1E-18)", -18);

        }

        private void comCategory_SelectedIndexChanged(object sender, EventArgs e)
        {            
            string[] arrString = ArrayCollection[comCategory.Text];

            lstFrom.Items.Clear();
            lstTo.Items.Clear();

            foreach(string curUnit in arrString)
            {
                lstFrom.Items.Add(curUnit);
                lstTo.Items.Add(curUnit);
            }        
        }

        private void lstFrom_SelectedIndexChanged(object sender, EventArgs e)
        {            
            if(lstFrom.SelectedIndex ==-1)
                   return;                

            switch(lstFrom.Text)
            {
                case "Meter":                     
                case "Gram":                    
                case "Liter":
                case "Sq Meter": 
                case "Cubic Meter": comPreFrom.Enabled = true;
                    comPreFrom.SelectedIndex = 8;
                    break;
                default: comPreFrom.Enabled = false;
                    comPreFrom.SelectedIndex = 8;
                    break;
            }
        }

        private void lstTo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lstTo.SelectedIndex == -1)
                return;

            switch (lstTo.Text)
            {
                case "Meter":
                case "Gram":
                case "Liter":
                case "Sq Meter":
                case "Cubic Meter": comPreTo.Enabled = true;
                    comPreTo.SelectedIndex = 8;
                    break;
                default: comPreTo.Enabled = false;
                    comPreTo.SelectedIndex = 8;
                    break;
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            string sCategory, sFrom, sTo, sResultRange;
            object[,] arrFromValue;
            decimal MetricMultiplyer;

            if (Globals.ThisAddIn.Application.ActiveSheet.Range(txtSource.Text).Cells.Count > 1)
            {
                arrFromValue = Globals.ThisAddIn.Application.ActiveSheet.Range(txtSource.Text).Value2;
            }
            else if ((Globals.ThisAddIn.Application.ActiveSheet.Range(txtSource.Text).Text).Length > 0)
            {
                Int32[] lowerBounds = { 1, 1 };
                Int32[] lengths = { 1, 1 };
                arrFromValue = (object[,])Array.CreateInstance(typeof(object), lengths, lowerBounds);
                arrFromValue[1, 1] = Globals.ThisAddIn.Application.ActiveSheet.Range(txtSource.Text).value2;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Source range is empty. Please select some numeric values");
                this.Activate();
                return;
            }

            
            sCategory = comCategory.Text;
            sFrom =  ReplaceToCategory.TryGetValue(lstFrom.Text, out sFrom)? sFrom : lstFrom.Text;
            sTo = ReplaceToCategory.TryGetValue(lstTo.Text, out sTo) ? sTo : lstTo.Text;

            if (chkOverwrite.Checked)
                sResultRange = txtSource.Text;
            else
                sResultRange = txtResult.Text;

            if (txtSource.Text.Length == 0)            
                MessageBox.Show("Please enter a range in 'Source Range'");                            
            else if (sResultRange.Length == 0)
                MessageBox.Show("Please enter a range in 'Result Range'");
            else if(lstFrom.Text.Length == 0 || lstTo.Text.Length ==0 )
                MessageBox.Show("Please select both 'From' unit and 'To' unit.");
            else if (lstFrom.Text == lstTo.Text && comPreFrom.Text == comPreTo.Text)            
                MessageBox.Show("'From' unit and 'To' unit are same.");
            else
            {
                Units.ConvertUnit(sCategory, sFrom, arrFromValue, sTo);
                if (comPreFrom.Enabled || comPreTo.Enabled)
                {
                    MetricMultiplyer = (decimal)((comPreFrom.Enabled ? Math.Pow(10, MetricFactors[comPreFrom.Text]) : 1) / (comPreTo.Enabled ? Math.Pow(10, MetricFactors[comPreTo.Text]) : 1));
                    for (int i = 1; i <= arrFromValue.GetLength(0); i++)
                        for (int j = 1; j <= arrFromValue.GetLength(1); j++)
                            arrFromValue[i, j] = (decimal)arrFromValue[i, j] * MetricMultiplyer;
                }
                Globals.ThisAddIn.Application.ActiveSheet.Range(sResultRange).Value2 = arrFromValue;
                this.Close();
            }            
        }

        private void txtResult_MouseClick(object sender, MouseEventArgs e)
        {
            Microsoft.Office.Interop.Excel.Range rng;
            rng = Globals.ThisAddIn.Application.InputBox("Please select range", "Select Range", txtResult.Text, this.Left - 5, this.Top + 5, Type: 8);
            rng.Select();
            txtResult.Text = rng.Address;
            this.Activate();

        }

        private void txtSource_Click(object sender, EventArgs e)
        {
            Microsoft.Office.Interop.Excel.Range rng;
            rng = Globals.ThisAddIn.Application.InputBox("Please select range", "Select Range", txtSource.Text, this.Left - 5, this.Top + 5, Type: 8);
            rng.Select();
            txtSource.Text = rng.Address;
            this.Activate();
        }

        private void chkOverwrite_CheckedChanged(object sender, EventArgs e)
        {
            txtResult.Enabled = (!chkOverwrite.Checked);            
        }

    }
}
